package pers.xiaojun.boot.common.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;


/**
 * Json 工具
 *
 * @author xiaojun
 * @since 2025-10-08
 */
@Slf4j
public class JsonUtils {

    @Setter
    private static ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 默认配置，后续会被新的 ObjectMapper 覆盖
     */
    static {
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 忽略空值
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.registerModule(new JavaTimeModule());
    }

    /**
     * 对象转Json字符串
     *
     * @param obj 对象
     * @return Json字符串
     */
    @SneakyThrows
    public static String toJson(Object obj) {
        return objectMapper.writeValueAsString(obj);
    }

    /**
     * 解析JSON字符串
     *
     * @param json Json字符串
     * @param cls  实例对象Class
     * @param <T>  实例类型
     * @return 解析后的对象实例
     */
    public static <T> T fromJson(String json, Class<T> cls) {
        if (StrUtil.isEmpty(json)) {
            return null;
        }
        try {
            return objectMapper.readValue(json, cls);
        } catch (JsonProcessingException e) {
            log.error("Failed to parse JSON \"{}\" into {}: ", json, cls.getName(), e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 解析JSON字符串，并获取其中的节点
     *
     * @param json JSON字符串
     * @param path 节点路径（一级）
     * @param cls  节点类型
     * @param <T>  节点类型
     * @return 节点对象
     */
    public static <T> T fromJsonAt(String json, String path, Class<T> cls) {
        if (StrUtil.isEmpty(json)) {
            return null;
        }
        try {
            JsonNode jsonNode = objectMapper.readTree(json);
            JsonNode pathNode = jsonNode.path(path);
            if (StrUtil.isEmpty(pathNode.toString())) {
                return null;
            }
            return objectMapper.readValue(pathNode.toString(), cls);
        } catch (JsonProcessingException e) {
            log.error("Failed to parse JSON path \"{}\" into {}: ", json, cls.getName(), e);
            throw new RuntimeException(e);
        }
    }

}
